//
//  LLPScrollView.m
//  LLP
//
//  Created by Porcellio on 10/16/12.
//  Copyright (c) 2012 Porcellio. All rights reserved.
//

#import "LLPScrollView.h"

#import "LLPScrollItem.h"
#import "LLPScrollItemView.h"
#import "AnimationHelper.h"

#define ITEMSPACING         5.0f
#define ITEMVIEWORIGINTAG   1024

@interface LLPScrollView (Private)

- (void)longPressGestureEvent:(UILongPressGestureRecognizer *)sender;
- (void)tapGestureEvent:(UITapGestureRecognizer *)sender;
- (void)itemViewGestureEvent:(UILongPressGestureRecognizer *)sender;
//- (void)panGestureEvent:(UIPanGestureRecognizer *)sender;

- (void)setStatus:(LLPScrollViewStatus)status;
- (void)setItemsEdit;
- (void)setItemsNormal;
- (void)setItemsLongGestureEnabled:(BOOL)enabled;

- (void)rearrangeItems:(UIView *)longPressedView;
- (NSInteger)getIndexByPosition:(CGPoint)point;

@end

static inline CGRect computeFrameWithIndex(NSInteger index, NSInteger columnCount, CGSize itemSize) {

    return CGRectMake((index % columnCount) * (itemSize.width + ITEMSPACING),
                      (index / columnCount) * (itemSize.height + ITEMSPACING) + ITEMSPACING,
                      itemSize.width, itemSize.height);
}

static inline CGSize resizeContentSize(NSInteger totalCount, NSInteger columnCount, CGSize itemSize) {

    if(columnCount == INT_MAX) {
        
        return CGSizeMake(totalCount * (ITEMSPACING + itemSize.width) - ITEMSPACING, 2 * ITEMSPACING + itemSize.height);
    }else {
        
        int nRow = totalCount / columnCount + (totalCount % columnCount == 0 ? 0 : 1);
        return CGSizeMake(columnCount * (ITEMSPACING + itemSize.width) - ITEMSPACING, nRow * (ITEMSPACING + itemSize.height));
    }
}

@implementation LLPScrollView

@synthesize items = _items;
@synthesize currentStatus = _currentStatus;
@synthesize isGestureEnable = _isGestureEnable;

- (id)initWithFrame:(CGRect)frame {
    
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
        _scrollView.delegate = self;
        _scrollView.showsVerticalScrollIndicator = NO;
        _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth
        | UIViewAutoresizingFlexibleHeight
        | UIViewAutoresizingFlexibleLeftMargin
        | UIViewAutoresizingFlexibleTopMargin;
        [self addSubview:_scrollView];
        [_scrollView release];
        
        _items = [[NSMutableArray arrayWithCapacity:10] retain];
        _itemSize = CGSizeMake(50.0f, 50.0f);
        _isGestureEnable = YES;
        _columnCount = INT_MAX;
        
        UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureEvent:)];
        [_scrollView addGestureRecognizer:tapGesture];
        [tapGesture release];
        
        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureEvent:)];
        [_scrollView addGestureRecognizer:longPressGesture];
        [longPressGesture release];
        
//        UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureEvent:)];
//        [_scrollView addGestureRecognizer:panGesture];
//        [panGesture release];
//        
//        for (UIGestureRecognizer *gestureRecognizer in _scrollView.gestureRecognizers) {
//            
//            [gestureRecognizer requireGestureRecognizerToFail:panGesture];
//        }
    }
    return self;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/

- (void)dealloc {

    [_items release];
    
    _items = nil;
    
    [super dealloc];
}

#pragma mark -
#pragma mark  - Instance Methods.

- (void)addItem:(LLPScrollItem *)item {

    if(item == nil)
        return;

    LLPScrollItemView *itemView = [[LLPScrollItemView alloc] initWithItem:item];
    itemView.backgroundColor = [UIColor colorWithRed:(arc4random() % 255 / 255.0f) green:(arc4random() % 255 / 255.0f) blue:(arc4random() % 255 / 255.0f) alpha:1.0f];
    if(itemView) {
    
        [_items addObject:item];
        item.superContentView = self;
        
        UILongPressGestureRecognizer *itemLongPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(itemViewGestureEvent:)];
        itemLongPressGesture.enabled = NO;
        itemLongPressGesture.minimumPressDuration = 0.3f;
        itemView.frame = computeFrameWithIndex(_items.count - 1, _columnCount, _itemSize);
        itemView.tag = ITEMVIEWORIGINTAG + _items.count - 1;
        [itemView addGestureRecognizer:itemLongPressGesture];
        [_scrollView addSubview:itemView];
        
        [itemLongPressGesture release];
        [itemView release];
        
        

        _scrollView.contentSize = resizeContentSize(_items.count, _columnCount, _itemSize);
    }
}

- (void)insertItem:(LLPScrollItem *)item atIndex:(NSInteger)index {

    if(item == nil || index < 0 || index >= _items.count)
        return;
    
    LLPScrollItemView *itemView = [[LLPScrollItemView alloc] initWithItem:item];
    if(itemView) {
        
        LLPScrollItemView *needMoveItemView = nil;
        for (int i = _items.count - 1; i >= index; --i) {
            
            needMoveItemView = (LLPScrollItemView *)[_scrollView viewWithTag:ITEMVIEWORIGINTAG + i];
            if(needMoveItemView) {
            
                needMoveItemView.frame = computeFrameWithIndex(i, _columnCount, _itemSize);
                ++needMoveItemView.tag;
            }
        }
        
//        [_items insertObject:itemView atIndex:index];
        [_items insertObject:item atIndex:index];
        item.superContentView = self;
        
        itemView.frame = computeFrameWithIndex(index, _columnCount, _itemSize);
        itemView.tag = ITEMVIEWORIGINTAG + index;
        [_scrollView addSubview:itemView];
        [itemView release];
        
        _scrollView.contentSize = resizeContentSize(_items.count, _columnCount, _itemSize);
    }
}

- (void)addItemsFromArray:(NSArray *)items {
    
    for (LLPScrollItem *item in items) {
        
        [self addItem:item];
    }
}

- (void)removeItem:(LLPScrollItem *)item {

    NSInteger index = [_items indexOfObject:item];
    if(index >= 0) {
    
        [self removeItemAtIndex:index];
    }
}

- (void)removeItemAtIndex:(NSInteger)index {

    if(index < 0 || index >= _items.count)
        return;
    
    LLPScrollItemView *itemView;
    itemView = (LLPScrollItemView *)[_scrollView viewWithTag:ITEMVIEWORIGINTAG + index];
    if(itemView) {
    
        [_items removeObjectAtIndex:index];
        [itemView removeFromSuperview];
        
        for (int i = index + 1; i < _items.count; i++) {
            
            itemView = (LLPScrollItemView *)[_scrollView viewWithTag:ITEMVIEWORIGINTAG + i];
            if(itemView) {
                
                itemView.frame = computeFrameWithIndex(i - 1, _columnCount, _itemSize);
                --itemView.tag;
            }
        }
        
        _scrollView.contentSize = resizeContentSize(_items.count, _columnCount, _itemSize);
    }
}

- (void)removeAllItems {

    [_items removeAllObjects];
    
    for (UIView *view in _scrollView.subviews) {
        
        if(view.tag >= ITEMVIEWORIGINTAG) {
        
            [view removeFromSuperview];
        }
    }
    
    _scrollView.contentSize = CGSizeMake(0.0f, 0.0f);
}

#pragma mark -
#pragma mark Private Methods.

- (void)longPressGestureEvent:(UILongPressGestureRecognizer *)sender {
    
    if(_currentStatus == LLPScrollViewNormalStatus) {
        
        CGPoint point = [sender locationInView:_scrollView];
        UIView *pressedView = [_scrollView hitTest:point withEvent:nil];
        if([pressedView isKindOfClass:[LLPScrollItemView class]]) {
        
            [self setStatus:LLPScrollViewEditStatus];
        }
        
        [self setItemsLongGestureEnabled:YES];
    }
}

- (void)tapGestureEvent:(UITapGestureRecognizer *)sender {

    if(_currentStatus == LLPScrollViewEditStatus) {
    
        [self setStatus:LLPScrollViewNormalStatus];
        
        [self setItemsLongGestureEnabled:NO];
    }
}

- (void)itemViewGestureEvent:(UILongPressGestureRecognizer *)sender {

    if(_currentStatus == LLPScrollViewEditStatus) {
    
        if(sender.state == UIGestureRecognizerStateBegan) {
        
            _longPressedView = sender.view;
            _lastIndex = _longPressedView.tag - ITEMVIEWORIGINTAG;
            [_scrollView bringSubviewToFront:_longPressedView];
            [AnimationHelper removeWobbleAnimationWithView:_longPressedView];
            [AnimationHelper addScaleAnimationWithView:_longPressedView];
            
        }else if(sender.state == UIGestureRecognizerStateChanged) {
            
            CGPoint point = [sender locationInView:_scrollView];
            if(_columnCount == INT_MAX) {
            
                _longPressedView.center = CGPointMake(point.x, _longPressedView.center.y);
            }else {
            
                _longPressedView.center = point;
            }
            
            [self rearrangeItems:_longPressedView];
            
        }else if(sender.state == UIGestureRecognizerStateCancelled ||
                 sender.state == UIGestureRecognizerStateEnded ||
                 sender.state == UIGestureRecognizerStateFailed) {
        
            [AnimationHelper removeScaleAnimationWithView:_longPressedView];
            [AnimationHelper addWobbleAnimationWithView:_longPressedView];
            
            _longPressedView.frame = computeFrameWithIndex([self getIndexByPosition:_longPressedView.center], _columnCount, _itemSize);
        }
    }
}

//- (void)panGestureEvent:(UISwipeGestureRecognizer *)sender {
//
//    NSLog(@"%d", sender.state);
//    
//    if(_currentStatus == LLPScrollViewNormalStatus) {
//    
//        CGPoint currentPoint = CGPointZero;
//        
//        if(sender.state == UIGestureRecognizerStateBegan) {
//            
//            _lastPoint = [sender locationInView:_scrollView];
//        
//        }else if(sender.state == UIGestureRecognizerStateChanged || sender.state == UIGestureRecognizerStateEnded) {
//            
//            currentPoint = [sender locationInView:_scrollView];
//            [_scrollView setContentOffset:CGPointMake(_scrollView.contentOffset.x + (_lastPoint.x - currentPoint.x),
//                                                      _scrollView.contentOffset.y)
//                                 animated:YES];
//            if(sender.state == UIGestureRecognizerStateEnded) {
//            
//                _lastPoint = CGPointZero;
//            }else {
//            
//                _lastPoint = currentPoint;
//            }
//        }
//    }
//}

- (void)setStatus:(LLPScrollViewStatus)status {
    
    if(!_isGestureEnable)
        return;
    
    _currentStatus = status;
    
    if(_currentStatus == LLPScrollViewEditStatus) {
    
        [self setItemsEdit];
    }else if(_currentStatus == LLPScrollViewNormalStatus) {
    
        [self setItemsNormal];
    }
}

- (void)setItemsEdit {

    for (UIView *view in _scrollView.subviews) {
        
        if(view.tag >= ITEMVIEWORIGINTAG) {
        
            [AnimationHelper addWobbleAnimationWithView:view];
        }
    }
}

- (void)setItemsNormal {
    for (UIView *view in _scrollView.subviews) {
        if(view.tag >= ITEMVIEWORIGINTAG) {
            [AnimationHelper removeWobbleAnimationWithView:view];
        }
    }
}

- (void)setItemsLongGestureEnabled:(BOOL)enabled {

    for (UIView *view in _scrollView.subviews) {
        
        if([view isKindOfClass:[LLPScrollItemView class]]) {
        
            ((LLPScrollItemView*)view).isEditing = enabled;
            for (UIGestureRecognizer *gestureRecognizer in view.gestureRecognizers) {
                
                if([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
                
                    gestureRecognizer.enabled = enabled;
                }
            }
        }
    }
}

- (void)rearrangeItems:(UIView *)longPressedView {

    int computedIndex = [self getIndexByPosition:longPressedView.center];
    
    [UIView animateWithDuration:0.25f animations:^{
    
        if(_lastIndex != computedIndex) {
            
            LLPScrollItem *tempItem;
            LLPScrollItemView *tempView;
            
            tempItem = [[_items objectAtIndex:_lastIndex] retain];
            [_items removeObjectAtIndex:_lastIndex];
            [_items insertObject:tempItem atIndex:computedIndex];
            [tempItem release];
            
            if(_lastIndex < computedIndex) {
                
                for (int i = _lastIndex + 1; i <= computedIndex; i++) {
                    
                    tempView = (LLPScrollItemView *)[_scrollView viewWithTag:ITEMVIEWORIGINTAG + i];
                    if(tempView) {
                        
                        tempView.frame = computeFrameWithIndex(i - 1, _columnCount, _itemSize);
                        tempView.tag--;
                    }
                }
            }else {
                
                for (int i = _lastIndex - 1; i >= computedIndex; i--) {
                    
                    tempView = (LLPScrollItemView *)[_scrollView viewWithTag:ITEMVIEWORIGINTAG + i];
                    if(tempView) {
                        
                        tempView.frame = computeFrameWithIndex(i + 1, _columnCount, _itemSize);
                        tempView.tag ++;
                    }
                }
            }
            
            _lastIndex = computedIndex;
            _longPressedView.tag = ITEMVIEWORIGINTAG + _lastIndex;
        }
    }];
}


- (NSInteger)getIndexByPosition:(CGPoint)point {

    int row = point.y / (ITEMSPACING + _itemSize.height);
    int column = point.x / (ITEMSPACING + _itemSize.width);
    int computedIndex = _columnCount == INT_MAX ? (column) : (row * _columnCount + column);
    
    return computedIndex;
}

#pragma mark -
#pragma mark UIScrollViewDelegate Support.



@end
